﻿using System;
using System.IO;
using System.Text;
using Itau.IM.Common.Constants;
using Itau.IM.Common.Interface;
using Itau.IM.Common.Utility;

namespace Itau.IM.Common.Logging
{
    /// <summary>
    /// Classe de gravação de log em arquivo
    /// </summary>
    public class LogFile : ILog
    {
        #region Atributos

        private StreamWriter _fileWriter;
        private string _routineName;
        private bool _logEnabled;

        #endregion Atributos

        #region Métodos

        /// <summary>
        /// Construtor
        /// </summary>
        /// <param name="routineName_">Nome da rotina</param>
        public LogFile(string routineName_)
        {
            this._logEnabled = Convert.ToBoolean(Configuration.GetSetting(LogConstants.LOG_ENABLED));
            this._routineName = routineName_;
        }

        /// <summary>
        /// Método responsável por inicializar o log da aplicação
        /// </summary>
        private void OpenLog()
        {
            try
            {
                string fileDirectory = Configuration.GetSetting(LogConstants.LOG_DIRECTORY);

                if (String.IsNullOrEmpty(fileDirectory))
                {
                    throw new Exception("Common: O diretório de log não foi corretamente definido no arquivo de configuração");
                }

                string fullFilePath = Path.Combine(fileDirectory, String.Format("{0}.log", this._routineName));

                if (!Directory.Exists(fileDirectory))
                {
                    Directory.CreateDirectory(fileDirectory);
                }

                if (!File.Exists(fullFilePath))
                {
                    this._fileWriter = File.CreateText(fullFilePath);
                }
                else
                {
                    this._fileWriter = new StreamWriter(fullFilePath, true, Encoding.UTF8);
                }
            }
            catch (Exception e)
            {
                throw new Exception("Common: Erro ao inicializar arquivo de log", e);
            }
        }

        /// <summary>
        /// Método responsável por fechar o arquivo de log
        /// </summary>
        private void CloseLog()
        {
            this._fileWriter.Close();
            this._fileWriter = null;
        }

        /// <summary>
        /// Método responsável por registrar o início do log da aplicação
        /// </summary>
        public void BeginLog()
        {
            try
            {
                if (this._logEnabled)
                {
                    this.OpenLog();
                    
                    this._fileWriter.WriteLine(LogConstants.LOG_SEPARATOR);
                    this._fileWriter.Flush();

                    this.CloseLog();

                    this.LogInfo("Iniciando log da rotina '{0}'", this._routineName);
                }
            }
            catch (Exception e)
            {
                throw new Exception("Common: Erro ao inicializar o arquivo de log", e);
            }
        }

        /// <summary>
        /// Método responsável por inserir uma informação no log da aplicação
        /// </summary>
        /// <param name="message_">Mensagem informativa</param>
        public void LogInfo(string message_)
        {
            try
            {
                if (this._logEnabled)
                {
                    this.OpenLog();

                    if (!ReferenceEquals(this._fileWriter, null))
                    {
                        string fullMessage = String.Format(LogConstants.LOG_INFO_MESSAGE, DateTime.Now, message_);

                        this._fileWriter.WriteLine(fullMessage);
                        this._fileWriter.Flush();

                        Console.WriteLine(fullMessage);
                    }
                    else
                    {
                        throw new Exception("Common: O arquivo de log não foi devidamente inicializado");
                    }

                    this.CloseLog();
                }
            }
            catch (Exception e)
            {
                throw new Exception("Common: Erro ao inserir informação no arquivo de log", e);
            }
        }

        /// <summary>
        /// Método responsável por inserir uma informação no log da aplicação
        /// </summary>
        /// <param name="message_">Mensagem informativa</param>
        /// <param name="arguments_">Argumetos da mensagem</param>
        public void LogInfo(string message_, params object[] arguments_)
        {
            this.LogInfo(String.Format(message_, arguments_));
        }

        /// <summary>
        /// Método responsável por registrar um erro no log da aplicação
        /// </summary>
        /// <param name="exception_">Objeto de exceção</param>
        public void LogError(Exception exception_)
        {
            try
            {
                if (this._logEnabled)
                {
                    this.OpenLog();

                    if (!ReferenceEquals(this._fileWriter, null))
                    {
                        string exceptionMessage = String.Format(LogConstants.LOG_ERROR_MESSAGE, DateTime.Now, exception_.Message);
                        string exceptionStackTrace = String.Format(LogConstants.LOG_ERROR_MESSAGE, DateTime.Now, exception_.StackTrace);

                        this._fileWriter.WriteLine(exceptionMessage);
                        this._fileWriter.WriteLine(exceptionStackTrace);

                        Console.WriteLine(exceptionMessage);
                        Console.WriteLine(exceptionStackTrace);

                        if (!ReferenceEquals(exception_.InnerException, null))
                        {
                            string innerExceptionMessage = String.Format(LogConstants.LOG_ERROR_MESSAGE, DateTime.Now, exception_.Message);
                            string innerExceptionStackTrace = String.Format(LogConstants.LOG_ERROR_MESSAGE, DateTime.Now, exception_.Message);

                            this._fileWriter.WriteLine(innerExceptionMessage);
                            this._fileWriter.WriteLine(innerExceptionStackTrace);

                            Console.WriteLine(innerExceptionMessage);
                            Console.WriteLine(innerExceptionStackTrace);
                        }

                        this._fileWriter.Flush();
                    }
                    else
                    {
                        throw new Exception("Common: O arquivo de log não foi devidamente inicializado");
                    }

                    this.CloseLog();
                }
            }
            catch (Exception e)
            {
                throw new Exception("Common: Erro ao registrar erro no arquivo de log", e);
            }
        }

        /// <summary>
        /// Método responsável por finalizar o log da aplicação
        /// </summary>
        public void FinishLog()
        {
            try
            {
                if (this._logEnabled)
                {
                    this.LogInfo("Finalizando arquivo de log da rotina '{0}'", this._routineName);
                    
                    this.OpenLog();

                    this._fileWriter.WriteLine(LogConstants.LOG_SEPARATOR);
                    this._fileWriter.Flush();

                    this.CloseLog();

                    Console.WriteLine(String.Empty);
                }
            }
            catch (Exception e)
            {
                throw new Exception("Common: Erro ao finalizar arquivo de log", e);
            }
        }

        #endregion Métodos
    }
}